#pragma once
#include <cstdint>
#include <vector>
#include <array>
#include <utility>
#include <numeric>

namespace clay {
    template<std::uint16_t charset_size>
    class ConnectBoard final {
    private:
        std::array<std::uint8_t, charset_size> mapping;
        bool isPlugged(const std::uint8_t value) const
        {
            return mapping.at(value) != value;
        }
    public:
        ConnectBoard()
        {
            std::iota(mapping.begin(), mapping.end(), 0);
        }


        ConnectBoard(const std::vector<std::pair<std::uint8_t, std::uint8_t>>& connect_pair_list)
        {
            std::iota(mapping.begin(), mapping.end(), 0);

            for (auto& pair : connect_pair_list) {
                if (pair.first >= charset_size || pair.second >= charset_size) {
                    // Uncomment the line below, will ignore this case.
                    // continue;
                }
                if (isPlugged(pair.first) || isPlugged(pair.second)) {
                    continue;
                }
                if (pair.first == pair.second) {    // Let it through also fine though.
                    continue;
                }

                mapping[pair.first] = pair.second;
                mapping[pair.second] = pair.first;
            }
        }


        std::uint8_t Map(const std::uint8_t value) const
        {
            return mapping.at(value);
        }


        std::uint8_t ReverseMap(const std::uint8_t value) const
        {
            return Map(value);
        }
    };
}